package com.atguigu.spzx.manager.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSON;
import com.atguigu.spzx.common.exception.GuiguException;
import com.atguigu.spzx.manager.mapper.SysRoleUserMapper;
import com.atguigu.spzx.manager.mapper.SysUserMapper;
import com.atguigu.spzx.manager.service.SysRoleUserService;
import com.atguigu.spzx.manager.service.SysUserService;
import com.atguigu.spzx.manager.service.ValidateCodeService;
import com.atguigu.spzx.manager.utils.AuthContextUtil;
import com.atguigu.spzx.model.constant.Constant;
import com.atguigu.spzx.model.dto.system.AssginRoleDto;
import com.atguigu.spzx.model.dto.system.LoginDto;
import com.atguigu.spzx.model.dto.system.SysUserDto;
import com.atguigu.spzx.model.entity.base.BaseEntity;
import com.atguigu.spzx.model.entity.system.SysRole;
import com.atguigu.spzx.model.entity.system.SysRoleUser;
import com.atguigu.spzx.model.entity.system.SysUser;
import com.atguigu.spzx.model.vo.common.ResultCodeEnum;
import com.atguigu.spzx.model.vo.system.LoginVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author：tzl
 * @Date：2024/1/15 17:32
 * @description: 用户
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {


    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private ValidateCodeService validateCodeService;

    @Autowired
    private SysRoleUserService sysRoleUserService;

    @Override
    public LoginVo login(LoginDto loginDto) {

        // 校验验证码是否正确
        validateCodeService.validateCode(loginDto);

        // 1、验证user是否存在
        String userName = loginDto.getUserName();
        SysUser user = getOne(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUsername, userName));

        // 2、不存在返回提示
        if (user == null) {
            throw new GuiguException(ResultCodeEnum.LOGIN_ERROR);
        }

        // 3、存在s验证密码是否正确
        // 4、密码不正确返回提示
        String userPassword = user.getPassword();
        String md5 = DigestUtils.md5DigestAsHex(loginDto.getPassword().getBytes());
        if (!userPassword.equals(md5)) {
            throw new GuiguException(ResultCodeEnum.LOGIN_ERROR);
        }

        // 5、验证通过生成token并存储至redis
        String token = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(Constant.USER_LOGIN + token, JSON.toJSONString(user),
                7, TimeUnit.DAYS);


        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        return loginVo;
    }

    @Override
    public void logout(String token) {
        redisTemplate.delete(Constant.USER_LOGIN + token);
    }

    @Override
    public SysUser getUserInfo() {
        return AuthContextUtil.get();
    }

    @Override
    public Page<SysUser> findByPage(SysUserDto sysUserDto, Integer pageNum, Integer pageSize) {
        Page<SysUser> page = this.page(new Page<>(pageNum, pageSize),
                new LambdaQueryWrapper<SysUser>()
                        .eq(StringUtils.isNotBlank(sysUserDto.getKeyword()), SysUser::getUsername, sysUserDto.getKeyword())
                        .ge(StringUtils.isNotBlank(sysUserDto.getCreateTimeBegin()), SysUser::getCreateTime, sysUserDto.getCreateTimeBegin())
                        .le(StringUtils.isNotBlank(sysUserDto.getCreateTimeEnd()), SysUser::getCreateTime, sysUserDto.getCreateTimeEnd()));

        return page;
    }

    @Override
    public void saveSysUser(SysUser sysUser) {
        SysUser dbUser = this.getById(sysUser.getId());
        if (dbUser != null) {
            throw new GuiguException(ResultCodeEnum.USER_NAME_IS_EXISTS);
        }

        // 修改密码为MD5
        String password = sysUser.getPassword();
        String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
        sysUser.setPassword(md5Password);
        sysUser.setStatus(0);
        this.save(sysUser);
    }

    @Override
    public void updateSysUser(SysUser sysUser) {
        // 不允许更改password
        if (!this.updateById(sysUser)) {
            throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
        }
    }

    @Override
    public void deleteById(Long userId) {
        if (!this.removeById(userId)) {
            throw new GuiguException(ResultCodeEnum.DELETE_ERROR);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void doAssign(AssginRoleDto assginRoleDto) {
        // 1、先删除原有的角色
        boolean delete = sysRoleUserService.remove(new LambdaQueryWrapper<SysRoleUser>()
                .eq(SysRoleUser::getUserId, assginRoleDto.getUserId()));
        // 2、添加分配角色
        List<SysRoleUser> sysRoleUsers = assginRoleDto.getRoleIdList().stream()
                .map(roleId -> {
                    SysRoleUser sysRoleUser = new SysRoleUser();
                    sysRoleUser.setUserId(assginRoleDto.getUserId());
                    sysRoleUser.setRoleId(roleId);
                    return sysRoleUser;
                }).collect(Collectors.toList());
        sysRoleUserService.saveBatch(sysRoleUsers);
    }
}
